
from time import ctime
from base64 import b64encode, b64decode
from os import path as os_path, mkdir, system, execv, makedirs, remove
from subprocess import Popen

from .utils import get_user_home
from .log import verbose, error


def _check_and_create_runcc_home():
    uhome = get_user_home()
    home = os_path.join(uhome, '.runcc')

    if not os_path.isdir(home):
        mkdir(home)
    
    return home


def _get_script_id(script_path: str):
    s = os_path.abspath(script_path)

    b64n = b64encode(s.encode('utf-8'))

    return b64n.decode('utf-8')


def _generate_compile_command(cxx_path: str, script_path: str, home: str, force):
    cmd = [cxx_path, script_path, '-o']

    mtime = os_path.getmtime(script_path)

    exe_dir = os_path.join(home, _get_script_id(script_path))
    if not os_path.exists(exe_dir):
        makedirs(exe_dir)

    version_path = os_path.join(exe_dir, 'version')
    need_to_compile = True

    if not force:
        with open(version_path, 'a+') as f:
            f.seek(0)
            v = f.read()
            
            # verbose('runcc: cache version:', v + '. current version:', mtime)

            if v == str(mtime):
                need_to_compile = False
            f.seek(0)
            f.truncate(0)
            f.write(str(mtime))
    

    exe_path = os_path.join(exe_dir, os_path.basename(script_path) + '.exe')
    if not os_path.exists(exe_path):
        need_to_compile = True

    if not need_to_compile:
        verbose('runcc: using cache: ' + exe_path)
    else:
        verbose('runcc: create executable at:', exe_path)

    cmd.append(exe_path)

    return cmd, exe_path, need_to_compile


def _exec_exe(cmd):
    process = Popen(cmd)
    process.wait()

    return process.returncode


def exec_script(cxx_path: str, script_path: str, args: list, prog_args) -> int:
    home = _check_and_create_runcc_home()

    cmd, exe_path, need_to_compile = _generate_compile_command(cxx_path, script_path, home, prog_args.force)
    cmd_str = ' '.join(cmd)

    if need_to_compile:
        verbose('runcc: compiler:', cmd_str)

        if _exec_exe(cmd):
            error('runcc: failed to compile script!')
            if os_path.exists(exe_path):
                remove(exe_path)
            return 1

    return _exec_exe([exe_path] + args)  # exec
